/*
 * Copyright 2013-2019 Xia Jun(3979434@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************************************
 *                                                                                     *
 *                        Website : http://www.farsunset.com                           *
 *                                                                                     *
 ***************************************************************************************
 */
package com.workcell.workdata.im.service.impl;

import com.workcell.workdata.im.component.event.MomentEvent;
import com.workcell.workdata.im.constant.ChangeType;
import com.workcell.workdata.im.entity.Comment;
import com.workcell.workdata.im.entity.Moment;
import com.workcell.workdata.im.model.vo.MomentVO;
import com.workcell.workdata.im.repository.CommentRepository;
import com.workcell.workdata.im.repository.MomentRepository;
import com.workcell.workdata.im.repository.specification.GallerySpecification;
import com.workcell.workdata.im.repository.specification.MomentSpecification;
import com.workcell.workdata.im.service.FriendService;
import com.workcell.workdata.im.service.MomentService;
import com.workcell.workdata.im.service.NotifiableListService;
import com.workcell.workdata.im.util.PageX;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
public class MomentServiceImpl implements MomentService {

	@Resource
	private MomentRepository momentRepository;

	@Resource
	private CommentRepository commentRepository;

	@Resource
	private ApplicationContext applicationContext;

	@Resource
	private NotifiableListService notifiableListService;

	@Resource
	private FriendService friendService;

	@Override
	public void add(Moment moment) {

		moment.setCreateTime(new Date());

		this.momentRepository.saveAndFlush(moment);

		applicationContext.publishEvent(new MomentEvent(moment, ChangeType.ADD));
	}

	@Override
	public void delete(long id) {

		commentRepository.deleteAll(id);

		Moment moment = momentRepository.findById(id).orElse(null);
		if (moment == null) {
			return;
		}

		this.momentRepository.deleteById(id);

		applicationContext.publishEvent(new MomentEvent(moment, ChangeType.DELETE));
	}

	@Override
	public Page<MomentVO> querySelfPage(Long uid, Pageable pageable) {

		Moment condition = new Moment();
		condition.setUid(uid);

		Page<Moment> page = momentRepository.findAll(Example.of(condition), pageable);

		if (page.isEmpty()){
			return PageX.map(MomentVO::of,page);
		}

		List<Long> idList = page.getContent().stream().map(Moment::getId).collect(Collectors.toList());

		List<Comment> comments = commentRepository.findList(idList);

		return PageX.map(moment -> {
			MomentVO vo = MomentVO.of(moment);
			vo.setCommentList(PageX.filter(new CommentPredicate(moment.getId()),comments));
			return vo;
		},page);

	}

	@Override
	public Page<MomentVO> queryOtherPage(Long uid, Long makerId, Pageable pageable) {

		Moment condition = new Moment();
		condition.setUid(makerId);

		Page<Moment> page = momentRepository.findAll(Example.of(condition), pageable);

		if (page.isEmpty()){
			return PageX.map(MomentVO::of,page);
		}

		boolean isFriend = friendService.isFriend(uid,makerId);


		Page<MomentVO> voPage = PageX.map(MomentVO::of,page);

		if (!isFriend){
			return voPage;
		}

		List<Long> uidList = notifiableListService.findList(makerId,uid);
		uidList.add(uid);
		uidList.add(makerId);

		List<Long> momentIdList = page.getContent().stream().map(Moment::getId).collect(Collectors.toList());

		List<Comment> comments = commentRepository.findList(momentIdList,uidList);

		for (MomentVO moment : voPage.getContent()) {
			moment.setCommentList(PageX.filter(new CommentPredicate(moment.getId()),comments));
		}
		return voPage;
	}

	@Override
	public Page<MomentVO> queryTimelinePage(Long uid, Pageable pageable) {

		List<Long> idList = notifiableListService.findVisibleList(uid);
		idList.add(uid);

		Page<Moment> page = momentRepository.findAll(MomentSpecification.of(idList), pageable);

		List<Long> momentIdList = page.getContent().stream().map(Moment::getId).collect(Collectors.toList());

		List<Comment> comments = commentRepository.findList(momentIdList,idList);

		return PageX.map(moment -> {
			MomentVO vo = MomentVO.of(moment);
			vo.setCommentList(PageX.filter(new CommentPredicate(moment.getId()),comments));
			return vo;
		},page);
	}

	@Override
	public MomentVO findOne(long id , long uid) {

		Moment moment = momentRepository.findById(id).orElse(null);
		if (moment == null) {
			return null;
		}

		MomentVO vo = MomentVO.of(moment);

		if (vo.getUid() == uid){
			vo.setCommentList(commentRepository.findList(moment.getId()));
			return vo;
		}

		List<Long> idList = notifiableListService.findList(uid);
		idList.add(uid);

		vo.setCommentList(commentRepository.findList(moment.getId(),idList));
		return vo;
	}

	@Override
	public List<MomentVO> queryListGallery(Long uid) {
		Pageable pageable = PageRequest.of(0, 5,Sort.by("id").descending());
		Page<Moment> page = momentRepository.findAll(GallerySpecification.of(uid), pageable);

		return page.getContent().stream().map(MomentVO::of).collect(Collectors.toList());
	}


	private static class CommentPredicate implements Predicate<Comment>{
		private final Long momentId;

		private CommentPredicate(Long momentId) {
			this.momentId = momentId;
		}

		@Override
		public boolean test(Comment comment) {
			return Objects.equals(comment.getMomentId(),momentId);
		}
	}

}
